package org.batatasframework.strategy;

import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.batatasframework.common.ParameterReader;
import org.batatasframework.monitor.LogonAccountMonitoring;
import org.batatasframework.util.RunningStatistics;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndViewDefiningException;

import cn.bonoon.kernel.security.LogonUser;
import cn.bonoon.kernel.security.LogonUserRuntimeCollection;
import cn.bonoon.kernel.util.StringHelper;


/**
 * 
 * <pre>
 * 新增加内容(20170905)：
 * 1. 在这里判断系统开放的规则，如果当前系统处于维护或禁止访问状态的，则直接返回相应的提示页面
 * 2. 在这里做访问量的限制，即这个服务器允许访问最大的人数是多少人，超过这个人数的，则重定向到另一个页面
 * 3. 可以抛出{@link ModelAndViewDefiningException}这个异常，让界面跳转到提示界面
 *     在{@link DispatcherServlet#processDispatchResult}(这个方式应该不行)
 * </pre>
 * 
 * 拦截url生成界面的，可以参考{@link org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter DefaultLoginPageGeneratingFilter}
 * 
 * @author jackson
 *
 * @see org.springframework.security.config.http.SecurityFilters
 * @see org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
 */
public class ServerStrategyFilter extends GenericFilterBean implements LogonAccountMonitoring{

	/** 这里是否能改为智能统计 */
	private RunningStatistics statistics = new RunningStatistics();
	
	private SessionRegistry sessionRegistry;
	
	private ServerStrategyHandler[] handlers;
	
	@Override
	public void afterPropertiesSet() throws ServletException {
		Assert.notEmpty(handlers, "必须定义策略的处理器！");
		
		Arrays.sort(handlers, new Comparator<ServerStrategyHandler>(){

			@Override
			public int compare(ServerStrategyHandler o1, ServerStrategyHandler o2) {
				return o1.getOrdinal() - o2.getOrdinal();
			}
			
		});
		
		for(ServerStrategyHandler handler : handlers){
			handler.init();
		}
		
		super.afterPropertiesSet();
	}
	
	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

		long s = System.currentTimeMillis();
        ServerStrategyEvent event = new ServerStrategyEvent(request);
		
        try{
	        /*
	         * 在这里先判断服务器是否已经关闭，如果已经关闭，则返回提示界面
	         * 有些处理则非优先的
	         */
	    	EXECUTE : for(ServerStrategyHandler handler : handlers){
	    		switch (handler.execute(response, event)) {
					case BREAK: break EXECUTE; 
					case RETURN: return;
				}
	    	}
        	
	        if(event.isRunable()){
	        	chain.doFilter(request, response);
	        }
        }finally{

        	long e = System.currentTimeMillis();
        	
	        if(event.hasLogon()){
	        	event.getLogon().getRuntime().visit(s, e);
	        }
	        
        	statistics.statistics(s, e);
        }
	}
	
	public void setHandlers(ServerStrategyHandler[] handlers) {
		this.handlers = handlers;
	}
	
	public void setSessionRegistry(SessionRegistry sessionRegistry) {
		this.sessionRegistry = sessionRegistry;
	}

	@Override
	public RunningStatistics getStatistics() {
		return statistics;
	}
	
	private LogonUserRuntimeCollection internalLogonUsers(SessionRegistry sessionRegistry, HttpServletRequest request, ParameterReader paraReader){
		List<Object> items = sessionRegistry.getAllPrincipals();
			
		int top = paraReader.getInteger("t", 100);
		if(top <= 0) top = items.size();
		
		String name = paraReader.getString("n");
		
		LogonUserRuntimeCollection runtimes = new LogonUserRuntimeCollection(request, statistics, items.size(), top);
		for(Object it : items){
			if(it instanceof LogonUser){
				LogonUser lu = (LogonUser)it;
				if(StringHelper.isNotEmpty(name) && !lu.getUsername().contains(name)){
					continue;
				}
				
				runtimes.add(lu.getRuntime());
				if(runtimes.size() >= top) break;
			}
		}
		
		//这里判断是否需要进行排序
		runtimes.sort(paraReader.getInteger("f", -1), paraReader.getString("s"));
		
		return runtimes;
	}

	@Override
	public LogonUserRuntimeCollection getLogonUsers(HttpServletRequest request, ParameterReader paraReader) {
		if(null != sessionRegistry){
			return internalLogonUsers(sessionRegistry, request, paraReader);
		}
		return null;
	}
	
	@Override
	public LogonUserRuntimeCollection userLogout(HttpServletRequest request, ParameterReader paraReader) throws Exception{
		if(null != sessionRegistry){
			int count = 0;
			for(String out : paraReader.arrayString("items")){
				SessionInformation si = sessionRegistry.getSessionInformation(out);
				if(null != si){
					si.expireNow();
					count++;
				}
			}
			
			//这里停一下子不知道行不行
			Thread.sleep(500);
			
			LogonUserRuntimeCollection lur = internalLogonUsers(sessionRegistry, request, paraReader);
			lur.setMessage("成功强制退出" + count + "个登录用户！");
			return lur;
		}
		return null;
	}
}
